// InterruptEvent.java
package org.zjx.core.model;

import lombok.Getter;
import org.zjx.core.DecisionNode;
import org.zjx.core.state.StateAccessor;

import java.time.Instant;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiPredicate;
import java.util.function.Supplier;

/**
 * 中断事件模型
 *
 * 表示一个可以中断正常决策流程的特殊事件。当中断事件被触发时，
 * 系统会跳转到指定的处理节点执行相应的逻辑。
 *
 * 中断事件具有优先级，高优先级的事件会优先被处理。
 */
@Getter
public class InterruptEvent implements Comparable<InterruptEvent> {
    /**
     * 中断事件优先级枚举
     *
     * 定义了三种优先级级别：
     * - CRITICAL(3): 致命级别，最高优先级
     * - HIGH(2): 高级别
     * - NORMAL(1): 正常级别，最低优先级
     */
    public enum Priority {
        CRITICAL(3), HIGH(2), NORMAL(1);
        final int level;  // 优先级级别值

        Priority(int level) {
            this.level = level;
        }  // 构造函数
    }

    private final Priority priority;      // 中断事件优先级
    private final String eventType;       // 中断事件类型，用于标识事件种类
    private final Supplier<DecisionNode> handler;  // 事件处理器，提供处理该事件的决策节点
    private final TriggerCondition triggerCondition;  // 触发条件，决定事件何时被触发
    private final Instant createTime = Instant.now();  // 事件创建时间，用于相同优先级事件的排序

    private final long coolDownMillis; // 冷却时间
    private volatile long lastTriggerTime;

    /**
     * 构造函数
     *
     * @param priority 中断事件优先级
     * @param eventType 中断事件类型
     * @param handler 事件处理器，提供处理该事件的决策节点
     * @param triggerCondition 触发条件，决定事件何时被触发
     */
    public InterruptEvent(Priority priority, String eventType,
                          Supplier<DecisionNode> handler,
                          TriggerCondition triggerCondition,
                          long coolDownMillis) {
        this.priority = priority;
        this.eventType = eventType;
        this.handler = handler;
        this.triggerCondition = triggerCondition;
        this.coolDownMillis = coolDownMillis;
    }

    /**
     * 使用状态访问器条件创建中断事件
     *
     * @param priority 中断事件优先级
     * @param eventType 中断事件类型
     * @param handler 事件处理器
     * @param condition 基于状态访问器和参数的条件函数
     * @return 创建的中断事件实例
     */

    public static InterruptEvent createWithAccessorCondition(
            Priority priority, String eventType,
            Supplier<DecisionNode> handler,
            BiPredicate<StateAccessor, Map<String, Object>> condition,
            long coolDownMillis) {
        return new InterruptEvent(priority, eventType, handler, condition::test, coolDownMillis);
    }

    /**
     * 判断中断事件是否被触发（基于StateAccessor）
     *
     * @param accessor 状态访问器，用于访问当前状态
     * @return 如果事件被触发返回true，否则返回false
     */
    public boolean isTriggered(StateAccessor accessor) {
        // 使用状态访问器获取状态快照，并调用另一个isTriggered方法进行判断
        return triggerCondition.test(accessor, Collections.emptyMap());
    }

    /**
     * 实现Comparable接口，用于中断事件的排序
     *
     * 排序规则：
     * 1. 首先按优先级降序排列（高优先级在前）
     * 2. 相同优先级的事件按创建时间升序排列（先创建的事件在前）
     *
     * @param other 另一个中断事件
     * @return 比较结果
     */
    @Override
    public int compareTo(InterruptEvent other) {
        // 先比较优先级级别值，降序排列
        int priorityCompare = Integer.compare(other.priority.level, this.priority.level);
        // 如果优先级相同，再比较创建时间，升序排列
        return priorityCompare != 0 ? priorityCompare :
                this.createTime.compareTo(other.createTime);
    }

    /**
     * 触发条件函数式接口
     *
     * 定义了判断中断事件是否被触发的条件函数。
     * 接受状态访问器、状态快照和参数映射作为输入，返回布尔值表示是否触发。
     */
    @FunctionalInterface
    public interface TriggerCondition {
        boolean test(StateAccessor accessor, Map<String, Object> params);
    }
}